#include<iostream>
#include<functional>
#include<vector>
#include<memory>
#include<unordered_map>
#include<unistd.h>

class timer{
public:
    timer(int taskfd,int timeout,std::function<void()> task)
    :taskfd_(taskfd),timeout_(timeout),task_(task)
    {}

    ~timer()
    {
        task_();
    }

    uint32_t DelayTime() { return timeout_; }

private:
    int taskfd_;//标识任务
    int timeout_;//间隔时间
    std::function<void()> task_;//执行任务
};

class TimerWheel{
public:
    TimerWheel(int tick=0,int capacity=60)
    :tick_(tick),capacity_(capacity),wheel(capacity)
    {
        wheel.resize(capacity);
    }

    //添加定时器
    void TimerAdd(int taskfd,int timeout,std::function<void()> task){
        std::shared_ptr<timer> st(new timer(taskfd,timeout,task));
        //加入时间轮中
        wheel[timeout].push_back(st);
        //加入哈希表中方便查找，使用weak_ptr因为引用计数不会增加
        fdmp[taskfd]=std::weak_ptr<timer>(st);
    }

    //判断是否已经加入时间轮中
    bool judg(int fd)
    {
        auto num=fdmp.begin();

        while(num!=fdmp.end())
        {
            if(num->first==fd){
                return true;
            }
            num++;
        }

        return false;
    }

    //刷新定时器
    void TimerRefresh(int taskfd){
        //判断
        if(!judg(taskfd))
        {
            std::cout<<"请先添加任务"<<std::endl;
            return ;
        }
        //通过fd找到weak_ptr,方便判断和构造对象
        std::shared_ptr<timer> sdelay=fdmp[taskfd].lock();
        //再次加入到时间轮当中
        wheel[tick_+sdelay->DelayTime()].push_back(sdelay);
    }


    //时间轮滚动
    void RunTimerTask()
    {
        tick_++;
        if(wheel[(tick_+capacity_)%60].size()>0)
        {
            //删除指针，引用计数为0的，自动调用析构函数执行任务
            wheel[(tick_+capacity_)%60].clear();
        }
    }

    //取消定时任务
    void TimerCancel(int fd)
    {
        fdmp.erase(fd);
    }

    ~TimerWheel()
    {}

private:
    int tick_;
    int capacity_;//表盘容量，也就是最多的延时时间
    std::vector<std::vector<std::shared_ptr<timer>>> wheel;//时间轮
    std::unordered_map<int,std::weak_ptr<timer>> fdmp;//通过fd找到weak_ptr,方便判断和构造对象，使用weak_ptr因为引用计数不会增加
};


class Test {
    public:
        Test() {std::cout << "构造" << std::endl;}
        ~Test() {std::cout << "析构" << std::endl;}
};

void DelTest(Test *t) {
    delete t;
}

int main()
{
    TimerWheel tw;

    Test *t = new Test();

    tw.TimerAdd(888, 5, std::bind(DelTest, t));

    for(int i = 0; i < 5; i++) {
        sleep(1);
        tw.TimerRefresh(888);//刷新定时任务
        tw.RunTimerTask();//向后移动秒针
        std::cout << "刷新了一下定时任务，重新需要5s中后才会销毁\n";
    }
    //tw.TimerCancel(888);
    while(1) {
        sleep(1);
        std::cout << "-------------------\n";
        tw.RunTimerTask();//向后移动秒针
    }
    return 0;
}
